package com.hehao.java_basic.concurrent;

import lombok.Data;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.util.concurrent.TimeUnit;

/**
 * @author Damon
 * @date 2023/6/15
 */
public class VolatileDemo {

    /**
     * 单次读写，volatile生效场景
     */
    public static class VolatileSingleReadAndWrite{
        //如果没有加volatile关键字，这时候线程A会一直陷入死循环，因为线程A监控不到stop值已经被主线程修改
        // private static  boolean stop = false;
        private static volatile boolean stop = false;

        public static void main(String[] args) {
            // Thread-A
            new Thread("Thread A") {
                @Override
                public void run() {
                    while (!stop) {
                    }
                    System.out.println(Thread.currentThread() + " stopped");
                }
            }.start();

            // Thread-main
            try {
                TimeUnit.SECONDS.sleep(1);
                System.out.println(Thread.currentThread() + " after 1 seconds");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            stop = true;
        }
    }


    /**
     * 多次读写，volatile失效场景
     */
    @Data
    public static class VolatileLoseEfficacy{
        private static final Logger logger = LogManager.getLogger(VolatileLoseEfficacy.class);

        public volatile int i;
        public void addI(){
            i++;
        }

        public static void main(String[] args) throws InterruptedException {
            VolatileLoseEfficacy volatileLoseEfficacy = new VolatileLoseEfficacy();
            for (int i = 0; i < 1000; i++) {
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        try {
                            Thread.sleep(10);
                            //这里加上日志输出的话会容易导致实验失效，日志打印有耗时并且sout底层是同步的，造成会有同步效果(并不是方法变同步)
                            //System.out.println("我是线程" + Thread.currentThread().getName());
                            //logger.info("我是线程" + Thread.currentThread().getName());
                        } catch (Exception e) {
                            e.printStackTrace();
                            throw new RuntimeException(e);
                        }
                        volatileLoseEfficacy.addI();
                    }
                }).start();
            }
            Thread.sleep(2000);
            logger.info("总数：{}",volatileLoseEfficacy.getI());
            System.out.println(volatileLoseEfficacy.getI());
        }
    }
}
